﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace ZhiHeng.OneCard.WpfClient.ViewModel
{
    public class FileSystemApplicationViewModel : ViewModelBase
    {
        public FileSystemApplicationViewModel()
            
        {
        }

        public IEnumerable<DriveData> Drives
        {
            get
            {
                ObservableCollection<DriveData> driveDataList = new ObservableCollection<DriveData>();
                foreach (var drive in DriveInfo.GetDrives())
                {
                    if (drive.DriveType != DriveType.Fixed) continue;

                    var driveData = new DriveData(drive);
                    driveDataList.Add(driveData);
                }
                return driveDataList;
            }
        }
    }

    /// <summary>
    /// Class FileSystemObjectData. Implements IDataErrorInfo to support Validation in the Editor.
    /// </summary>
    public class FileSystemObjectData : INotifyPropertyChanged, IDataErrorInfo
    {
        protected virtual void RaisePropertyChanged(string propertyName)
        {
            var h = PropertyChanged;
            if (h != null)
                h(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public string DisplayName
        {
            get
            {
                return String.Format("{0} ({1})", Name, Type);
            }
        }


        private string _Name;
        public string Name
        {
            get { return _Name; }
            set
            {
                _Name = value;
                RaisePropertyChanged("Name");
                RaisePropertyChanged("DisplayName");
            }
        }

        private long? _Size;
        public long? Size
        {
            get { return _Size; }
            set
            {
                if (value > 0)
                    _Size = value;
                else
                    _Size = null;
                RaisePropertyChanged("Size");
            }
        }

        public string Type { get; set; }

        private DateTime? _CreationTime;
        public DateTime? CreationTime
        {
            get { return _CreationTime; }
            set
            {
                if (value != _CreationTime)
                {
                    _CreationTime = value;
                    RaisePropertyChanged("CreationTime");
                }
            }
        }
        public DateTime LastAccessTime { get; set; }

        private FileAttributes? _Attributes;
        public FileAttributes? Attributes
        {
            get { return _Attributes; }
            set
            {
                _Attributes = value;
                RaisePropertyChanged("Attributes");
            }
        }

        public int HierarchyLevel { get; protected set; }

        private Uri _ImageSource;
        public Uri ImageSource
        {
            get { return _ImageSource; }
            set
            {
                if (value != _ImageSource)
                {
                    _ImageSource = value;
                    RaisePropertyChanged("ImageSource");
                }
            }
        }

        private bool _IsExpanded;
        public bool IsExpanded
        {
            get { return _IsExpanded; }
            set
            {
                if (_IsExpanded != value)
                {
                    _IsExpanded = value;
                    RaisePropertyChanged("IsExpanded");
                }
            }
        }

        private bool? _IsChecked;
        public bool? IsChecked
        {
            get { return _IsChecked; }
            set
            {
                if (value != _IsChecked)
                {
                    _IsChecked = value;
                    RaisePropertyChanged("IsChecked");
                }
            }
        }

        protected static IList<FolderContentObjectData> GenerateChildren(DirectoryInfo dirInfo, int hierarchyLevel)
        {
            var list = new ObservableCollection<FolderContentObjectData>();

            try
            {
                foreach (var dir in dirInfo.GetDirectories())
                {
                    if ((dir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
                        continue;
                    var folder = new FolderData(dir, hierarchyLevel + 1);
                    list.Add(folder);
                }
            }
            catch (UnauthorizedAccessException) { }

            try
            {
                foreach (var fileInfo in dirInfo.GetFiles())
                {
                    var file = new FileData(fileInfo);
                    list.Add(file);
                }
            }
            catch (UnauthorizedAccessException) { }
            return list;
        }

        public string Error
        {
            get { return null; }
        }

        /// <summary>
        /// Implementation of IDataErrorInfo for use by the default Editor for Cells or Nodes.
        /// </summary>
        public string this[string columnName]
        {
            get
            {
                if (columnName == "Name")
                {
                    if (String.IsNullOrEmpty(Name))
                        return "Name cannot be empty.";
                    else if (!IsValidFileName(Name))
                    {
                        return @"Name cannot contain any of the following characters: <,>,:,"",/,\,|,?,*";
                    }
                }

                return null;
            }
        }

        private bool IsValidFileName(string name)
        {
            if (name.Contains('<'))
                return false;
            if (name.Contains('>'))
                return false;
            if (!(this is DriveData) && name.Contains(':'))
                return false;
            if (name.Contains('"'))
                return false;
            if (name.Contains('/'))
                return false;
            if (name.Contains('\\'))
                return false;
            if (name.Contains('|'))
                return false;
            if (name.Contains('?'))
                return false;
            if (name.Contains('*'))
                return false;

            return true;
        }
    }

    public class FolderContentObjectData : FileSystemObjectData
    {

    }

    /// <summary>
    /// Class FolderData
    /// </summary>
    public class FolderData : FolderContentObjectData
    {
        private DirectoryInfo _DirInfo;
        public FolderData()
        {
        }

        public FolderData(DirectoryInfo dirInfo, int hierarchyLevel)
        {
            _DirInfo = dirInfo;
            HierarchyLevel = hierarchyLevel;
            Name = _DirInfo.Name;
            Attributes = _DirInfo.Attributes;
            CreationTime = _DirInfo.CreationTime;
            LastAccessTime = _DirInfo.LastAccessTime;
            IsExpanded = false;// hierarchyLevel <= 2;
            ImageSource = new Uri("Images/FolderOpen.png", UriKind.Relative);
            Type = "Folder";
        }

        public FileSystemObjectData Find(string name)
        {
            foreach (var obj in Children)
            {
                if (obj.Name == name) return obj;
                var f = obj as FolderData;
                if (f != null)
                {
                    var c = f.Find(name);
                    if (c != null) return c;
                }
            }
            return null;
        }

        private IList<FolderContentObjectData> _Children;
        public IList<FolderContentObjectData> Children
        {
            get
            {
                if (_Children == null)
                    _Children = FileSystemObjectData.GenerateChildren(_DirInfo, HierarchyLevel);
                return _Children;
            }
        }


        protected override void RaisePropertyChanged(string propertyName)
        {
            base.RaisePropertyChanged(propertyName);

            if (GetType() == typeof(FolderData))
                ImageSource = IsExpanded ? new Uri("Images/FolderOpen.png", UriKind.Relative) : new Uri("Images/FolderClosed.png", UriKind.Relative);
        }



    }

    /// <summary>
    /// Class FileData
    /// </summary>
    public class FileData : FolderContentObjectData
    {
        public List<FolderContentObjectData> Children { get { return null; } }

        private FileInfo _FileInfo;

        public FileData()
        {

        }

        public FileData(FileInfo fileInfo)
        {
            _FileInfo = fileInfo;
            Name = _FileInfo.Name;
            Size = _FileInfo.Length;
            CreationTime = _FileInfo.CreationTime;
            Attributes = _FileInfo.Attributes;
            LastAccessTime = _FileInfo.LastAccessTime;
            Type = "File";
            ImageSource = new Uri("Images/File.png", UriKind.Relative);

            IsChecked = false;
        }
    }


    /// <summary>
    /// Class DriveData
    /// </summary>
    public class DriveData : FileSystemObjectData
    {
        DriveInfo _DriveInfo;
        public DriveData()
        { }

        public DriveData(DriveInfo drive)
        {
            _DriveInfo = drive;
            Name = drive.Name.Replace(@"\", "");
            Size = drive.TotalSize;
            Type = "Local Disk";
            IsExpanded = true;
            ImageSource = new Uri(@"Images\Harddrive.png", UriKind.RelativeOrAbsolute);
        }

        private IList<FolderContentObjectData> _Children;
        public IList<FolderContentObjectData> Children
        {
            get
            {
                if (_Children == null)
                    _Children = FileSystemObjectData.GenerateChildren(_DriveInfo.RootDirectory, 1);
                return _Children;
            }
        }
    }
}
